package com.guaoran.common.utils;

import com.guaoran.common.domain.Demo;

import java.io.File;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;

/**
 * @author : 孤傲然
 * @description : MockUtil
 * @date :2020/7/6 16:28
 */
public class MockUtil {
    private static final Map<String,Object> DEFAULT_VALUE_MAP = new HashMap();
    private static final List<String> IGNORE = new ArrayList<>();
    static {
        String methods = "getClass,clone,valueOf,notify,wait,notifyAll,equals,compareTo,hashCode";
        IGNORE.addAll(Arrays.asList(methods.split(",")));
        DEFAULT_VALUE_MAP.put("java.lang.String", "\"STR\"");
        DEFAULT_VALUE_MAP.put("java.lang.Integer", 1);
        DEFAULT_VALUE_MAP.put("java.lang.Long", "1L");
        DEFAULT_VALUE_MAP.put("java.util.Date", "new java.util.Date()");
        DEFAULT_VALUE_MAP.put("java.util.Map", "new java.util.HashMap()");
        DEFAULT_VALUE_MAP.put("default", "new Object()");
        DEFAULT_VALUE_MAP.put("boolean", "true");
        DEFAULT_VALUE_MAP.put("char", "'1'");
        DEFAULT_VALUE_MAP.put("long", "1L");
        DEFAULT_VALUE_MAP.put("int", 1);
    }

    private List<String> registerBeanClasses = new ArrayList<>();
    private List<Class> classes = new ArrayList<>();

    /**
     * 扫描目录下面的所有文件和递归扫描子包文件
     *
     * @param packageName
     */
    private void doScanner(String packageName) {
        Class clazz = Demo.class;
        String absolutePathPrefix = clazz.getProtectionDomain().getCodeSource().getLocation().getPath();
        if(packageName == null){
            packageName = clazz.getName();
            packageName = packageName.substring(0,packageName.lastIndexOf("."));
        }
        // 将文件中的 com.guaoran.common.domain 转换成具体的文件路径 com/guaoran/common/domain 加载到 registyBeanClasses中
        String absolutePath = absolutePathPrefix.concat(packageName.replaceAll("\\.", "/"));
        File classDir = new File(absolutePath);
        if (classDir.exists()) {
            for (File file : classDir.listFiles()) {
                if (file.isDirectory()) {
                    doScanner(packageName + "." + file.getName());
                } else {
                    registerBeanClasses.add(packageName + "." + file.getName().replace(".class", ""));
                }
            }
        }
    }

    public static void main(String[] args) {
        MockUtil mockUtil = new MockUtil();
        mockUtil.doScanner(null);
        mockUtil.doRegistry();
        mockUtil.doCreate();
    }

    private void doRegistry(){
        registerBeanClasses.forEach(className -> {
            try {
                Class<?> beanClass = Class.forName(className);
                if(!className.contains("$")){
                    classes.add(beanClass);
                }
            } catch (ClassNotFoundException e) {
            }
        });
    }

    private void doCreate() {
        StringBuilder sb = new StringBuilder();
        sb.append("public void test() { ").append("\n");
        StringBuilder sbClass = new StringBuilder();
        for (Class temp : classes) {
            if(temp.isEnum()){
                // 如果是枚举
                doCreateEnum(sb,temp);
            }else{
                // 是类
                doCreateClass(sb,sbClass,temp);
            }
        }
        sb.append("}").append("\n");
        System.out.println(sbClass.toString());
        System.out.println("\n\n");
        System.out.println(sb.toString());
    }

    private void doCreateClass(StringBuilder sb, StringBuilder sbClass, Class temp) {
        String className = getClassName(temp.getName());
        sbClass
            .append("@org.springframework.beans.factory.annotation.Autowired ")
            .append(className).append(" ")
            .append(lowerFirstCase(className))
            .append(";").append("\n\n") ;

        // 执行函数方法
        Method[] methods = temp.getMethods();
        for (final Method method : methods) {
            if (IGNORE.contains(method.getName())) {
                continue;
            }
            sb
            .append("\t").append(lowerFirstCase(className))
            .append(".").append(getMethod(method.getName())).append("(");

            sb = getParams(method,sb);
            sb.append(");").append("\n");
        }
    }

    private void doCreateEnum(StringBuilder sb, Class temp) {
        String className = getClassName(temp.getName());
        sb
        .append("\t").append(className).append("[] ")
        .append(lowerFirstCase(className)).append("Arr")
        .append("=").append(className).append(".values();").append("\n")
        .append("\t").append("for (").append(className).append(" ").append(lowerFirstCase(className))
        .append(" : ").append(lowerFirstCase(className)).append("Arr").append(") { \n");
        // 执行函数方法
        Method[] methods = temp.getMethods();
        for (final Method method : methods) {
            if (IGNORE.contains(method.getName())) {
                continue;
            }
            // 静态方法过滤
            if(Modifier.isStatic(method.getModifiers())){
                continue;
            }

            sb.append("\t\t").append(lowerFirstCase(className)).append(".").append(getMethod(method.getName())).append("(");

            sb = getParams(method,sb);
            sb.append(");").append("\n");
        }
        sb.append("\t}\n\n");

    }

    private StringBuilder getParams(Method method, StringBuilder sbMethod){
        final Class<?>[] parameterTypes = method.getParameterTypes();
        if (parameterTypes.length > 0) {
            for (int i = 0; i < parameterTypes.length; i++) {
                String name = parameterTypes[i].getName();
                Object value = DEFAULT_VALUE_MAP.get(name);
                if(value == null){
                    value = "new " + name + "()";
                }
                sbMethod.append(value);
                if(i != parameterTypes.length -1){
                    sbMethod.append(" , ");
                }
            }
        }
        return sbMethod;
    }
    private String lowerFirstCase(String str) {
        char[] chars = str.toCharArray();
        if(chars[0]<98) {
            chars[0] += 32;
        }
        return String.valueOf(chars);
    }

    private String getClassName(String fullName){
        return fullName.substring(fullName.lastIndexOf(".")+1);
    }
    private String getMethod(String fullMethod){
        return fullMethod.substring(fullMethod.lastIndexOf(".")+1);
    }
}
